package com.cqs.learning.spring.cloud.producer.config;

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;

/**
 * 限流规则
 *
 * @author lixw
 * @date created in 15:17 2020/4/5
 */
@Configuration
@Log4j2
public class SentinelRulesConfig {

    /**
     * 限流全局资源
     */
    public static final String GLOBAL_RESOURCE_NAME_KEY = "FLOW_RULE_UNIQUE_KEY";
    public static final String GLOBAL_RESOURCE_NAME_KEY_AUTHORITY = "FLOW_RULE_UNIQUE_KEY_AUTHORITY";
//    public static final String GLOBAL_RESOURCE_NAME_KEY_AUTHORITY = GLOBAL_RESOURCE_NAME_KEY;
    /**
     * 全局限QPS最大值
     */
    private static final int GLOBAL_RESOURCE_LIMIT_CNT = 10000;

    /***
     * 方案一  不区分接口限速 + 单机 + 白名单
     * 本地设置流控规则
     */
    @PostConstruct
    public void initFlowDegradeRule() {
        //添加规则
        List<FlowRule> rules = new ArrayList<>();
        //QPS全局限制
        Supplier<FlowRule> supplier = () -> {
            FlowRule rule = new FlowRule();
            rule.setResource(GLOBAL_RESOURCE_NAME_KEY);
            //最大支持并发数量
            rule.setCount(GLOBAL_RESOURCE_LIMIT_CNT);
            rule.setLimitApp("default_app");
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
            rule.setMaxQueueingTimeMs(1000);
            log.info("资源{}新增熔断规则--Grade{},Count:{}", rule.getResource(), rule.getGrade(), rule.getCount());
            return rule;
        };

        //仅仅对appA生效
        FlowRule ruleApp = supplier.get();
        ruleApp.setResource(GLOBAL_RESOURCE_NAME_KEY_AUTHORITY);
        //白名单的元素进行限速 单独限速
        ruleApp.setLimitApp("appA");
        ruleApp.setCount(5);
        rules.add(ruleApp);
        rules.add(supplier.get());
        FlowRuleManager.loadRules(rules);
    }

    /***
     * 方案一  不区分接口限速 + 单机 + 白名单
     */
    @PostConstruct
    public void initAuthorityRule() {
        //开启白名单
        AuthorityRule rule = new AuthorityRule();
        rule.setResource(GLOBAL_RESOURCE_NAME_KEY_AUTHORITY);
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
        //對appA,appC,appE 應用
        rule.setLimitApp("appA,appE");
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
//        log.info("资源{}新增限流规则--getLimitApp:{},getStrategy:{}", rule.getResource(), rule.getLimitApp(), rule.getStrategy());
    }


    /**
     * 熔断(降级)规则
     */
    @PostConstruct
    public void initDegradeRules() {
//        //DegradeServiceImpl定义了
//        String resourceName = "fuseResource";
//        List<DegradeRule> rules = new ArrayList<>();
//        DegradeRule rule = new DegradeRule();
//        //最少请求次数才能触发
//        rule.setMinRequestAmount(2);
//        //异常比例 -- 方便观察
//        rule.setCount(0.05);
//        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
//        //时间窗口10秒钟
//        rule.setTimeWindow(10);
//        rule.setResource(resourceName);
////        rule.setLimitApp("default_app");
//        rules.add(rule);
//        DegradeRuleManager.loadRules(rules);
//        log.info("添加熔断规则:{}", DegradeRuleManager.getRules());
    }

    @PostConstruct
    private static void initDegradeRule() {
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        DegradeRule rule = new DegradeRule();
        rule.setResource("fuseResource");
        // set limit exception ratio to 0.1
//        rule.setCount(0.01);
//        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
        rule.setCount(1);
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        rule.setTimeWindow(10);
        rule.setMinRequestAmount(1);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
        log.info("添加熔断规则:{}", DegradeRuleManager.getRules());
    }
}
